package com.simple.trade.service.vm.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Suppliers;
import com.google.common.base.Throwables;
import com.google.gson.Gson;
import com.simple.common.entity.ResData;
import com.simple.common.entity.constant.Payment;
import com.simple.common.entity.dto.pay.vm.VmBaseDto;
import com.simple.common.entity.po.sys.ChannelComp;
import com.simple.common.entity.po.sys.Product;
import com.simple.ds.service.ChannelService;
import com.simple.ds.service.ProductService;
import com.simple.ds.service.TradeApi;
import com.simple.trade.holder.PayContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.Objects;

/**
 * @author yasud
 * @date 2020年09月30日 09:16
 * @description
 */
@Slf4j
public abstract class AbstractService {

    @Autowired
    protected ChannelService channelService;

    @Autowired
    protected ProductService productService;

    @Autowired
    protected TradeApi tradeApi;

    @Autowired
    protected ObjectMapper objectMapper;

    @Autowired
    protected Gson gson;


    /**
     * 找到渠道和产品
     *
     * @return
     */
    protected Pair<ChannelComp, Product> findChannelAnProduct() {
        ChannelComp channel = PayContext.current().channel();
        Product product = PayContext.current().product();
        return Pair.of(channel, product);
    }

    @Autowired
    LoadBalancerClient loadBalancerClient;

    @Autowired
    RestTemplate restTemplate;

    /**
     * 这里用rest方式最简单，
     * 内部接口相互通信全部使用post
     *
     * @param directPayDto
     * @param channel
     */
    @SneakyThrows
    public <R> ResData<R> forwardToChannel(VmBaseDto directPayDto, ChannelComp channel, Payment.PAY_TYPE type, Class<R> responseClass) {
        log.info("交易{}请求渠道{}开始参数为{}", directPayDto.getTrade().getId(), channel.getCode(), objectMapper.writeValueAsString(directPayDto));
        ServiceInstance instance = loadBalancerClient.choose(channel.getServiceProvider());
//        Preconditions.checkNotNull(instance, "The service is starting. Please try again later");
        if (Objects.isNull(instance)) {
            return ResData.error("The service is starting. Please try again later");
        }
        ResData resData = Suppliers.memoize(() -> {
            try {
                ResponseEntity<String> responseEntity = restTemplate.postForEntity(getServiceUrl(instance, type), directPayDto, String.class);
                ResData rResData = objectMapper.readValue(responseEntity.getBody(), ResData.class);
                return rResData;
            } catch (Exception ex) {
                ex.printStackTrace();
                return ResData.error(Throwables.getRootCause(ex).getMessage());
            }
        }).get();
        R r = objectMapper.readValue(objectMapper.writeValueAsString(resData.getData()), responseClass);
        resData.setData(r);
        log.info("交易{}请求渠道{}结束返回{}", directPayDto.getTrade().getId(), channel.getCode(), objectMapper.writeValueAsString(resData));
        return resData;
    }

    private String getServiceUrl(ServiceInstance instance, Payment.PAY_TYPE type) {
        return "http://" + instance.getServiceId() + "/" + type.code;
    }
}
